﻿using System.Diagnostics;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService.Symbols;

/// <summary>
///     类或接口类型的符号
/// </summary>
public class NamedTypeSymbol : AbstractTypeSymbol
{
    private readonly List<ITypeSymbol> _interfaces = [];


    private ITypeSymbol? _baseType;

    internal NamedTypeSymbol(ObjectTypeSignature objectType, ModuleSymbol? containingModule) :
        base(SymbolKinds.NamedType,
            objectType.IsNode(SyntaxKinds.ClassSignature) ? TypeKinds.Class : TypeKinds.Interface)
    {
        Declaration = objectType;
        ContainingModule = containingModule;
        LocationMap.AddLocation(objectType.NameIdentifier.GetLocation());
    }


    public override string Name => Declaration.Name;

    public override ObjectTypeSignature Declaration { get; }

    public override ModuleSymbol? ContainingModule { get; }

    public override ISymbol? ContainingSymbol => ContainingModule;

    public override ITypeSymbol? BaseType => _baseType;

    public override IReadOnlyList<ITypeSymbol> Interfaces => _interfaces;


    public override bool IsInterface => Declaration.IsNode(SyntaxKinds.InterfaceSignature);

    public override bool IsClass => Declaration.IsNode(SyntaxKinds.ClassSignature);

    public override bool IsObjectType => true;

    public override bool CanMakeArray => !IsModule;


    private bool AddProperty(PropertySymbol property)
    {
        if (property.IsDefault)
        {
            if (DefaultProperty != null)
            {
                return false;
            }

            DefaultProperty = property;
        }

        if (property.Name.Equals("Item", StringComparison.OrdinalIgnoreCase))
        {
            if (IndexerProperty != null)
            {
                return false;
            }

            IndexerProperty = property;
        }

        return NamedMembers.DeclareSymbol(property);
    }


    private bool AddMethod(MethodSymbol method)
    {
        if (method.IsDefault && DefaultMethod != null)
        {
            return false;
        }

        if (method.IsDefault)
        {
            DefaultMethod = method;
        }

        return NamedMembers.DeclareSymbol(method);
    }


    private bool AddConstant(LocalSymbol constant)
    {
        Debug.Assert(constant.IsConstant);
        bool result = NamedMembers.DeclareSymbol(constant);
        if (result)
        {
            WithConstant = true;
        }

        return result;
    }


    internal override bool TryAddMember(ISymbol member)
    {
        switch (member.Kind)
        {
            case SymbolKinds.Property:
                return AddProperty((PropertySymbol)member);

            case SymbolKinds.Method:
                return AddMethod((MethodSymbol)member);

            case SymbolKinds.Constant:
                Debug.Assert(TypeKind == TypeKinds.Class);
                return AddConstant((LocalSymbol)member);

            default:
                return false;
        }
    }


    /// <summary>
    ///     设定一个基类，如果当前的基类不是空或者接口列表中有同名列表，返回<see langword="false" />
    /// </summary>
    internal bool Inherit(ITypeSymbol baseType)
    {
        if (BaseType != null)
        {
            Debug.Assert(IsClass);
            return false;
        }

        if (IsClass)
        {
            _baseType = baseType;
        }
        else
        {
            if (_interfaces.FirstOrDefault(i =>
                    i.FullName.Equals(baseType.FullName, StringComparison.OrdinalIgnoreCase)) != null)
            {
                return false;
            }

            _interfaces.Add(baseType);
        }

        return true;
    }


    /// <summary>
    ///     向实现列表中添加一个新的接口类型，如果指定名称的接口已存在，返回<see langword="false" />
    /// </summary>
    internal bool Implement(ITypeSymbol interfaceType)
    {
        Debug.Assert(IsClass);
        if (_interfaces.FirstOrDefault(i =>
                i.FullName.Equals(interfaceType.FullName, StringComparison.OrdinalIgnoreCase)) != null)
        {
            return false;
        }

        _interfaces.Add(interfaceType);
        return true;
    }


    /// <summary>
    ///     类或接口类型在查找命名成员时，会向上查找继承或实现的类型、接口，
    ///     如果在所有相关类型中都没有找到，返回<see langword="null" />
    /// </summary>
    /// <param name="name">成员名，不能是全名</param>
    public override ITypeSymbol? LookupNamedMember(string name)
    {
        ITypeSymbol? symbol = base.LookupNamedMember(name);
        // 查找基类
        symbol ??= BaseType?.LookupNamedMember(name);
        // 查找接口
        if (symbol != null)
        {
            return symbol;
        }

        foreach (ITypeSymbol? i in _interfaces)
        {
            symbol = i.LookupNamedMember(name);
            if (symbol != null)
            {
                break;
            }
        }

        return symbol;
    }


    public override bool HasInterface(ITypeSymbol symbol)
    {
        if (!symbol.IsInterface)
        {
            return false;
        }

        if (_interfaces.Contains(symbol))
        {
            return true;
        }

        return BaseType != null && BaseType.HasInterface(symbol);
    }


    public override bool IsAssignableFrom(ITypeSymbol type)
    {
        // 模块符号不能被赋值
        if (IsModule || type.IsModule)
        {
            return false;
        }

        // 非类型符号不可赋值
        if (!type.IsClass || !type.IsInterface)
        {
            return false;
        }

        if (!IsClass)
        {
            return !IsInterface || type.HasInterface(this);
        }

        if (type.IsInterface)
        {
            return false;
        }

        // 如果此符号是类，则只有同一个类或派生类才能赋值
        ITypeSymbol? t = type;
        while (t != null)
        {
            if (t == this)
            {
                return true;
            }

            t = t.BaseType;
        }

        return false;
    }
}